package com.zenchn.aspect;


import com.zenchn.annotation.OperLog;
import com.zenchn.aspect.service.BuildSaveLogService;
import com.zenchn.aspect.utils.LogAspectUtils;
import com.zenchn.entity.WebPlatformAccessLog;
import com.zenchn.enums.OperLogStatusEnum;
import com.zenchn.model.TSysAccount;
import com.zenchn.utils.IPUtils;
import com.zenchn.utils.Ip2RegionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/***
 *  AccessLogAspect.java ：
 *  控制器 操作访问日志记录AOP类
 * @author panbingqi
 * @date 2021-06-01
 */
@Aspect
@Order(1)
@Component
public class AccessLogAspect {
    private static final Logger log = LoggerFactory.getLogger(AccessLogAspect.class);

    @Autowired
    private BuildSaveLogService buildSaveLogService;


    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.zenchn.annotation.OperLog)")
    public void logPointCut() {}

    /**
     * 后置通知 拦截正常操作
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        handleOperLog(joinPoint,null);
    }

    /**
     *后置通知  拦截异常操作
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) {
        handleOperLog(joinPoint,e);

    }

    private  void handleOperLog(JoinPoint joinPoint, Exception e) {
        try {
            //接收到请求，记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();

            WebPlatformAccessLog accessLog = new WebPlatformAccessLog();

            accessLog.setRequestURL(request.getRequestURL().toString());
            accessLog.setRequestURI(request.getRequestURI());
            accessLog.setQueryString(request.getQueryString());
            accessLog.setRemoteAddr(request.getRemoteAddr());
            accessLog.setRemoteHost(request.getRemoteHost());
            accessLog.setRemotePort(request.getRemotePort());
            accessLog.setLocalAddr(request.getLocalAddr());
            accessLog.setLocalName(request.getLocalName());

            // 获得注解
            OperLog controllerLog = getAnnotationLog(joinPoint);
            if (controllerLog != null) {
                // 设置 操作行为动作
                accessLog.setAction(controllerLog.action().name());
                // 设置 操作模块
                accessLog.setModule(controllerLog.module());
                // 设置 操作详情
                accessLog.setDetail(controllerLog.detail());
            }
            accessLog.setMethod(request.getMethod());


            accessLog.setHeaders(LogAspectUtils.getHeadersInfo(request));
            accessLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());

            // 是否需要保存request，参数和值
            if (null!=controllerLog){
                if(controllerLog.isSaveRequestData()) {
                accessLog.setParameters(LogAspectUtils.getParameterMap(request));
                accessLog.setArgs(LogAspectUtils.getArgs(joinPoint.getArgs()));
                }
            }else {
                accessLog.setParameters(LogAspectUtils.getParameterMap(request));
                accessLog.setArgs(LogAspectUtils.getArgs(joinPoint.getArgs()));
            }
            //操作系统
            accessLog.setOperatingSystem(LogAspectUtils.getOsName(request));
            //浏览器
            accessLog.setBrowser(LogAspectUtils.getBrowserName(request) + "(" + LogAspectUtils.getBrowserVersion(request) + ")");
            // 访问IP
            accessLog.setAccessIp(IPUtils.getRealIP(request));
            // 请求位置
            accessLog.setAccessLocation(Ip2RegionUtils.getCleanAddress(accessLog.getAccessIp()));

            //异常信息
            if (null != e) {
                accessLog.setStatus(OperLogStatusEnum.ERROR.getDesc());
                accessLog.setErrorMsg(e.getMessage());
            } else {
                accessLog.setStatus(OperLogStatusEnum.NORMAL.getDesc());
            }
            accessLog.setOperTime(new Date());

            // 判断用户是否登录
            Subject subject = SecurityUtils.getSubject();
            //如果用户没有登录,跳转到登录页面
            if (subject.isAuthenticated()) {
                final TSysAccount currAccount = (TSysAccount) subject.getPrincipal();
                // 获取当前的用户
                if (currAccount != null) {
                    accessLog.setOperAccName(currAccount.getRealName());
                    accessLog.setOperAccId(currAccount.getAccountId());
                }
            }

//            buildSaveLogService.saveAccessLog(accessLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("操作日志记录异常:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 是否存在操作日志注解，如果存在就获取
     */
    private OperLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(OperLog.class);
        }
        return null;
    }
}
